package top.banner.contentcenter.auth;

import io.jsonwebtoken.Claims;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import top.banner.contentcenter.utils.JwtOperator;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;

@Aspect
@Component
public class AuthAspect {
    @Resource
    private JwtOperator jwtOperator;


    @Around("@annotation(top.banner.contentcenter.auth.CheckLogin)")
    public Object checkLogin(ProceedingJoinPoint point) throws Throwable {
        checkToken();
        return point.proceed();
    }

    /**
     * 检验Token是否合法
     */
    private void checkToken() {
        //获取token
        final HttpServletRequest request = getRequest();

        final String token = request.getHeader("X-Token");

        //校验token是否合法
        final Boolean isValid = jwtOperator.validateToken(token);
        if (!isValid) {
            throw new SecurityException("Token不合法!");
        }
        //如果校验成功，就将信息设置到request的attribute中
        final Claims claims = jwtOperator.getClaimsFromToken(token);

        request.setAttribute("id", claims.get("id"));
        request.setAttribute("wxNickname", claims.get("wxNickname"));
        request.setAttribute("role", claims.get("role"));
    }

    private HttpServletRequest getRequest() {
        final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        final ServletRequestAttributes attributes = (ServletRequestAttributes) requestAttributes;
        assert attributes != null;
        return attributes.getRequest();
    }

    @Around("@annotation(top.banner.contentcenter.auth.CheckAuthorization)")
    public Object checkAuthorization(ProceedingJoinPoint point) throws Throwable {
        try {
            this.checkToken();

            final HttpServletRequest request = getRequest();
            final String role = request.getAttribute("role").toString();

            final MethodSignature signature = (MethodSignature) point.getSignature();
            final Method method = signature.getMethod();
            final CheckAuthorization annotation = method.getAnnotation(CheckAuthorization.class);
            final String value = annotation.value();

            if (!Objects.equals(role, value)) {
                throw new SecurityException("用户无权访问");
            }
        } catch (Throwable e) {
            throw new SecurityException("用户无权访问", e);
        }
        return point.proceed();
    }
}
